#include <AST/expr/control/ForAST.hpp>
#include <global.hpp>
#include <AST/expr/var/VarAST.hpp>
#include <AST/expr/literal/BoolAST.hpp>
#include <AST/expr/control/IfAST.hpp>
#include <AST/expr/AnyGenAST.hpp>

For::For(Expr *init, Expr *condition, Expr *step, Expr *body)
    : init(init), condition(condition), step(step), body(body) {
    // 如果无条件，则永远为true
    if (condition == nullptr) this->condition = new Bool(true);
}

llvm::Value *For::codegen() {
    auto scopeGuard = theScope.guard();
    Function *fun = builder.GetInsertBlock()->getParent();

    if (init != nullptr) {
        if (init->codegen() == nullptr)
            return logError("For::codegen: emit 'init' failed");
    }

    // 设置锚点
    BasicBlock *forCondBlock = BasicBlock::Create(theContext, "forCond", fun);
    BasicBlock *forBodyBlock = BasicBlock::Create(theContext, "forBody");
    BasicBlock *forEndBlock = BasicBlock::Create(theContext, "forEnd");
    theScope.setBreakPoint(forEndBlock);
    theScope.setContinuePoint(forCondBlock);

    // 显式跳转到循环
    builder.CreateBr(forCondBlock);

    // 写循环Block
    builder.SetInsertPoint(forCondBlock);

    builder.CreateCondBr(condition->codegen(), forBodyBlock, forEndBlock);

    // 处理循环体
    fun->getBasicBlockList().push_back(forBodyBlock);
    builder.SetInsertPoint(forBodyBlock);
    if (body != nullptr) {
        if (body->codegen() == nullptr)
            return logError("For::codegen: body codegen failed");
    }

    // 处理 step
    // 获取最新Block
    forBodyBlock = builder.GetInsertBlock();
    if (forBodyBlock->getTerminator() != nullptr && step != nullptr) {
        std::cerr << "[Warning] step in forLoop is ignored"
                " because a terminator is found\n";
    }
    if (forBodyBlock->getTerminator() == nullptr && step != nullptr) {
        if (step->codegen() == nullptr)
            return logError("For:codegen: step codegen failed");
    }

    // 获取最新Block
    forBodyBlock = builder.GetInsertBlock();
    if (forBodyBlock->getTerminator() == nullptr)
        builder.CreateBr(forCondBlock);

    // 处理循环结束
    fun->getBasicBlockList().push_back(forEndBlock);
    builder.SetInsertPoint(forEndBlock);

    // TODO: 还原stack保护外部变量

    // XXX: 正常返回void
    return llvm::UndefValue::get(BasicType::VoidTy);
}